home *** CD-ROM | disk | FTP | other *** search
/ The World's Largest Collection of Windows Software / The World's Largest Collection of Windows Software - Disc 1.iso / connect / _j2 / wvnsc926 / wvheader.c < prev    next >
C/C++ Source or Header  |  1994-09-21  |  38KB  |  1,442 lines

  1. /* --- WVHEADER.C ---------------------------------------------
  2.  *
  3.  *  This file contains the code necessary to create the initial skeleton
  4.  *  version of an article, which will be edited by the user.
  5.  *
  6.  *  Mark Riordan   24-JAN-1990
  7.  */
  8.  
  9.  
  10. /*
  11.  *
  12.  * $Id: wvheader.c 1.26 1994/09/16 00:42:53 jcooper Exp $
  13.  * $Log: wvheader.c $
  14.  * Revision 1.26  1994/09/16  00:42:53  jcooper
  15.  * cc-by-mail feature and cleanup for 92.6
  16.  *
  17.  * Revision 1.25  1994/08/24  18:40:15  mrr
  18.  * authorization enables post/mail
  19.  *
  20.  * Revision 1.24  1994/05/27  01:29:29  rushing
  21.  * unnecessary winundoc.h
  22.  *
  23.  * Revision 1.23  1994/02/24  21:31:49  jcoop
  24.  * jcoop changes
  25.  *
  26.  * Revision 1.22  1994/02/09  18:01:08  cnolan
  27.  * cnolan 90.2 changes
  28.  *
  29.  * Revision 1.21  1994/01/18  09:51:34  jcoop
  30.  * Use new version number scheme on X-Mailer header line
  31.  *
  32.  * Revision 1.20  1994/01/15  20:31:16  jcoop
  33.  * Font/color stuff and signature file handling
  34.  * 
  35.  * Revision 1.19  1993/12/08  01:27:21  rushing
  36.  * new version box and cr lf consistency
  37.  * 
  38.  * Revision 1.18  1993/08/25  18:53:17  mbretherton
  39.  * MRB merge, mail & post logging
  40.  *
  41.  *
  42.  * remove underscore for BC++ compile   Bretherton
  43.  *
  44.  * Revision 1.17  1993/08/17  21:53:06  UNKNOWN
  45.  * Updated version to Version 0.82 (JD)
  46.  *
  47.  * Revision 1.16  1993/07/13  22:11:31  rushing
  48.  * strncpy crashing in parseaddress
  49.  *
  50.  * Revision 1.15  1993/07/06  21:09:50  cnolan
  51.  * win32 support
  52.  *
  53.  * Revision 1.14  1993/06/29  20:06:07  rushing
  54.  * use localtime for Date header
  55.  *
  56.  * Revision 1.13  1993/06/29  00:22:13  rushing
  57.  * correct rfc822/rfc1036 MakeArtHeaderDate function
  58.  *
  59.  * Revision 1.12  1993/06/28  17:51:21  rushing
  60.  * warnings
  61.  *
  62.  * Revision 1.11  1993/06/22  19:08:40  rushing
  63.  * remove warnings
  64.  *
  65.  * Revision 1.10  1993/06/22  16:46:33  bretherton
  66.  * robust parse_address
  67.  *
  68.  * Revision 1.9  1993/06/11  01:05:17  rushing
  69.  * new version number
  70.  *
  71.  * Revision 1.8  1993/06/11  00:11:26  rushing
  72.  * second merge from Matt Bretherton sources
  73.  *
  74.  *
  75.  * Revision 1.7  1993/05/24  23:34:12  rushing
  76.  * further refinements to header manipulation
  77.  * extend reuse of header formatting capabilities
  78.  *
  79.  *
  80.  * Revision 1.5  1993/05/18  22:10:45  rushing
  81.  * smtp support
  82.  *
  83.  * Revision 1.4  1993/05/06  19:44:10  rushing
  84.  * CompareStringNoCase was using _tolower rather than tolower.
  85.  * according to c70 docs, _tolower is undefined for letters that
  86.  * are not uppercase.  Yikes!
  87.  *
  88.  * Revision 1.3  1993/04/30  21:17:01  rushing
  89.  * put the X-Newsreader: line back in.
  90.  *
  91.  * Revision 1.2  1993/03/30  20:07:37  rushing
  92.  * MAPI
  93.  *
  94.  * Revision 1.1  1993/02/16  20:54:22  rushing
  95.  * Initial revision
  96.  *
  97.  *
  98.  */
  99.  
  100. #include <windows.h>
  101. #include <windowsx.h>
  102. #include "wvglob.h"
  103. #include "winvn.h"
  104. #pragma hdrstop
  105. #include <ctype.h>
  106. #include <time.h>
  107. #include <stdlib.h>
  108.  
  109. #define MAXHEADERLINE 256
  110. int NewDocType;
  111.  
  112. BOOL (*PostHeaderFuncs[])(TypDoc * Doc, char *Buf, long int BufLen) =
  113. {
  114.     MakeArtHeaderFrom,
  115.     MakeArtHeaderNewsgroups,
  116.     MakeArtHeaderSubject,
  117. /* MakeArtHeaderMessageID, */
  118. /* MakeArtHeaderDate,      */
  119.     MakeArtHeaderReferences,
  120.     MakeArtHeaderOrganization,
  121.     MakeArtHeaderReplyTo,
  122.     MakeArtHeaderNewsreader,
  123.     NULL
  124. };
  125.  
  126.  
  127. /*--- function GetHeaderLine -------------------------------------------
  128.  *
  129.  *  Given a document, get a line from the header portion of that document
  130.  *  whose prefix matches a given prefix.  Prefix = first word in line.
  131.  *  For instance, you might call this routine to say "Get the 'Subject:'"
  132.  *  line from this document.
  133.  *
  134.  *    Entry    Doc      points to the document whose header we are scanning.
  135.  *                      The header is all the lines up to the first blank line.
  136.  *             Prefix   is the character string which will identify the
  137.  *                      line we are seeking.  It is the first word
  138.  *                      (blank-delimited) in a line in the header.
  139.  *             BufLen   is the number of bytes left in the buffer Buf.
  140.  *
  141.  *    Exit     Returns TRUE iff we returned a line.
  142.  *             Buf      if line was returned, contains that line, zero-
  143.  *                      terminated.
  144.  */
  145. BOOL
  146. GetHeaderLine (Doc, Prefix, Buf, BufLen)
  147.      TypDoc *Doc;
  148.      char *Prefix;
  149.      char *Buf;
  150.      int BufLen;
  151. {
  152.   char *bufptr = Buf;
  153.   TypBlock far *BlockPtr;
  154.   TypLine far *LinePtr;
  155.   unsigned int Offset;
  156.   HANDLE hBlock;
  157.   TypLineID MyLineID;
  158.   int found = FALSE;
  159.  
  160.   TopOfDoc (Doc, &BlockPtr, &LinePtr);
  161.   while (ExtractTextLine (Doc, LinePtr, Buf, BufLen))
  162.     {
  163.  
  164.       /* Is this a blank line signifying the end of the header?      */
  165.  
  166.       if (IsLineBlank (Buf))
  167.    break;
  168.  
  169.       if (CompareStringNoCase (Buf, Prefix, strlen (Prefix)) == 0)
  170.    {
  171.      found = TRUE;
  172.      break;
  173.    }
  174.       if (!NextLine (&BlockPtr, &LinePtr))
  175.    break;
  176.     }
  177.   UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
  178.   return (found);
  179. }
  180.  
  181. /*--- function CreatePostingWnd -----------------------------------------
  182.  *
  183.  *    Create the window for composing the text of a posting,
  184.  *    if it's OK to post.
  185.  *
  186.  *    Entry    Hwnd     Handle to parnet window
  187.  *             Doc      points to the document to which we are posting
  188.  *                      a followup--NULL if it's a new posting.
  189.  *
  190.  *    Exit     Returns the handle of the newly-created window
  191.  *              (zero if failure).
  192.  */
  193.  
  194. HWND
  195. CreatePostingWnd (hWnd,Doc, DocType)
  196.      HWND hWnd ;
  197.      TypDoc *Doc;
  198.      int DocType;
  199. {
  200.   int ih;
  201.   BOOL found = FALSE;        
  202.   BOOL AuthReq;
  203.   unsigned int width;
  204.   char *TitlePtr, *WndName;      
  205.   
  206.   if (DocType == DOCTYPE_POSTING)
  207.     {          
  208.       AuthReq = AuthReqPost;
  209.       WndName = "WinVnPost";
  210.       PostDoc = Doc;
  211.       if (Doc)
  212.    {
  213.      TitlePtr = "Composing Followup Article";
  214.    }
  215.       else
  216.    {
  217.      TitlePtr = "Composing New Article";
  218.    }
  219.       for (ih = 0; !found && ih < MAXPOSTWNDS; ih++)
  220.    {
  221.      if (!WndPosts[ih].hWnd)
  222.        {
  223.          found = TRUE;
  224.          break;
  225.        }
  226.    }
  227.     }
  228.   else
  229.     {         
  230.       AuthReq = AuthReqMail;
  231.       WndName = "WinVnMail";
  232.       MailDoc = Doc;
  233.       if (Doc)
  234.    {
  235.      TitlePtr = "Composing Reply Message";
  236.    }
  237.       else
  238.    {
  239.      TitlePtr = "Composing New Mail Message";
  240.      strcpy(AddressString,"") ;
  241.    }
  242.       for (ih = 0; !found && ih < MAXMAILWNDS; ih++)
  243.    {
  244.      if (!WndMails[ih].hWnd)
  245.        {
  246.          found = TRUE;
  247.          break;
  248.        }
  249.    }
  250.     }
  251.   if (found && AuthenticatePosting (AuthReq))
  252.     {
  253.  
  254.       if (xScreen > 78 * ArtCharWidth)
  255.    {
  256.      width = 78 * ArtCharWidth;
  257.    }
  258.       else
  259.    {
  260.      width = xScreen - 2 * ArtCharWidth;
  261.    }
  262.  
  263.       hWnd = CreateWindow (WndName,
  264.             TitlePtr,
  265.             WS_OVERLAPPEDWINDOW /* | WS_VSCROLL */ ,
  266.             /* Initial X pos */
  267.             ih * CharWidth,
  268.             /* Initial Y pos */
  269.             (int) (yScreen * 3 / 8) + (1 + ih) * LineHeight,
  270.             /* Initial X Width */
  271.             (int) width,
  272.             /* Initial Y height */
  273.             (int) (yScreen * 5 / 8) - (2 * LineHeight),
  274.             NULL,
  275.             NULL,
  276.             hInst,
  277.             NULL);
  278.  
  279.       if (hWnd)
  280.    {
  281.      SetHandleBkBrush (hWnd, hArticleBackgroundBrush);        
  282.      ShowWindow (hWnd, SW_SHOWNORMAL);
  283.      UpdateWindow (hWnd);
  284.    }
  285.     }
  286.   return (hWnd);
  287. }
  288.  
  289.  
  290. /*--- function CreatePostingText ------------------------------------------
  291.  *
  292.  *    Create the text of the skeleton article to be edited by
  293.  *    the user before posting.   Display that text in an edit window.
  294.  */
  295. BOOL
  296. CreatePostingText (Doc, hWndPost, hWndEdit, DocType)
  297.      TypDoc *Doc;
  298.      HWND hWndPost;
  299.      HWND hWndEdit;
  300.      int DocType;
  301. {
  302.   char far *lpTextBuffer;
  303.   HANDLE hTextBuffer;
  304.   int nLines;
  305.   long lParam;
  306.  
  307.   if (NULL == (hTextBuffer = ExtractPostingText(Doc,DocType)))
  308.     {
  309.       MessageBox (hWndPost, "Cannot allocate memory for text", "", MB_OK);
  310.       return FALSE;
  311.     }
  312.   lpTextBuffer = GlobalLock(hTextBuffer) ;
  313.  
  314.   /*  Set the edit window text to this skeleton article.            */
  315.  
  316.  
  317.   SetWindowText (hWndEdit, lpTextBuffer);
  318.   FreePostingText (hTextBuffer);
  319.  
  320.   nLines = (int) SendMessage (hWndEdit, EM_GETLINECOUNT, 0, 0L);
  321.   lParam = (long) ((long) nLines);
  322.  
  323.   return TRUE;
  324. }
  325.  
  326. /*--------- Extract the Text for the Posting ---------------------------
  327.  *
  328.  *    Entry    Doc      points to the document to which we are posting
  329.  *                      a followup--NULL if it's a new posting. *  
  330.  *             DocType  either build skeletal mail or posting document
  331.  *
  332.  *    Exit      a pointer to the unlocked memory area for skeletal posting
  333.  *
  334.  *  Remember to call FreePosting Text to reclaim the memory allocated to
  335.  *  the posting text 
  336.  */
  337.  
  338. HANDLE
  339. ExtractPostingText (Doc, DocType)
  340.      TypDoc *Doc;
  341.     int DocType;
  342. {
  343.   long int BytesLeft;
  344.   char far *lpTextBuffer;
  345.   BOOL (**HeaderFuncs) (TypDoc * Doc, char *Buf, long int BufLen);
  346.   char far *lpCurPtr;
  347.   HANDLE hTextBuffer;
  348.   BOOL gotline;
  349.   char line[MAXHEADERLINE];
  350.   int ifunc;
  351.  
  352.   NewDocType = DocType;
  353.   if (DocType == DOCTYPE_POSTING)
  354.     {
  355.       HeaderFuncs = PostHeaderFuncs;
  356.     }
  357.   else
  358.     {
  359.      HeaderFuncs = MailCtrl.MailHeaderFuncs;
  360.     }
  361.  
  362.   /* Compute the number of bytes we need to hold a straight ASCII representation
  363.    * of the initial text of the reply, and allocate a buffer of that size.
  364.    */
  365.   if (Doc)
  366.     {
  367.       BytesLeft = (2 + NumBlocksInDoc (Doc)) * Doc->BlockSize;
  368.     }
  369.   else
  370.     {
  371.       BytesLeft = 3000;
  372.     }
  373.  
  374.   if (NULL == (hTextBuffer = GlobalAlloc (GHND, (DWORD) BytesLeft)))
  375.     {
  376.        return ((HANDLE) NULL) ;
  377.     }
  378.  
  379.   lpCurPtr = lpTextBuffer = GlobalLock (hTextBuffer);
  380.  
  381.   for (ifunc = 0; HeaderFuncs[ifunc]; ifunc++)
  382.     {
  383.      gotline = (HeaderFuncs[ifunc]) (Doc, line, (long int) MAXHEADERLINE);
  384.       if (gotline)
  385.    {
  386.          AppendTextToEditBuf (line, &lpCurPtr, &BytesLeft);
  387.    }
  388.     }
  389.   MakeArtBody (Doc, &lpCurPtr, &BytesLeft, DocType);
  390.  
  391.   GlobalUnlock (hTextBuffer);
  392.   return(hTextBuffer) ;
  393.   }
  394. /*---------- FreePostingText ---------------------------------------------
  395.  *
  396.  * Free the memory of the skeletal posting text
  397.  *
  398.  */
  399. BOOL
  400. FreePostingText (hTextBuffer)
  401.   HANDLE hTextBuffer;
  402. {
  403.   GlobalUnlock (hTextBuffer);
  404.   GlobalFree (hTextBuffer);
  405.   
  406.   strcpy(AddressString,"") ;
  407.   strcpy(NameString,"") ;
  408.   strcpy(DialogString,"") ;
  409.  
  410.   return(TRUE) ;
  411. }
  412.  
  413. /*--- functions MakeArtHeaderXXXXX ---------------------------------------
  414.  *
  415.  *   Functions with names of the form MakeArtHeaderXxxxxx are all called
  416.  *   the same way and have similar purposes.  They are called to
  417.  *   create and return a line of text that will become a line in
  418.  *   the header of an article to be posted.  The source of
  419.  *   this information varies; it may be taken from an article
  420.  *   being replied to, it may be taken from a configuration file,
  421.  *   read from the system clock, etc.
  422.  *
  423.  *    Entry    Doc      points to a document containing an article
  424.  *                      being replied to; NULL if we're not replying
  425.  *                      to an article.
  426.  *             BufLen   is the length of the output buffer.
  427.  *
  428.  *    Exit     Returns TRUE iff we returned a line.
  429.  *             Buf      contains the line, if any, terminated by a
  430.  *                      zero byte.
  431.  */
  432.  
  433. /*--- function MakeArtHeaderSubject -------------------------------------
  434.  *
  435.  *    Returned "Subject:" 
  436.  *
  437.  */
  438.  
  439. BOOL
  440. MakeArtHeaderSubject (Doc, Buf, BufLen)
  441.      TypDoc *Doc;
  442.      char *Buf;
  443.      long int BufLen;
  444. {
  445.   char *outptr = Buf;
  446.   char from[MAXHEADERLINE];
  447.   char *fromptr;
  448.   
  449.   CopyBuf ("Subject: ", &outptr, &BufLen);
  450.   if (Doc)
  451.     {
  452.       GetArtHeaderSubject (Doc, NULL, NULL);
  453. //    if (!DialogString[0])   // always allow reply-subject confirmation
  454.      
  455.       if (NewDocType == DOCTYPE_POSTING) {
  456.         fromptr = from;    
  457.         if (GetHeaderLine (Doc, "From:", from, MAXHEADERLINE-1))
  458.           {
  459.              NextToken (&fromptr);
  460.              ParseAddress (fromptr, CcAddress, MAXDIALOGSTRING , str, MAXINTERNALLINE ) ;
  461.           } else
  462.               CcAddress[0] = (char) NULL;
  463.       }
  464.       DialogBoxParam (hInst, "WinVnSubject", Doc->hDocWnd, lpfnWinVnSubjectDlg, (LPARAM)(NewDocType == DOCTYPE_POSTING));
  465.     }
  466.   else
  467.     {
  468.       DialogString[0] = (char) NULL;
  469.       CcAddress[0] = (char) NULL;
  470.  
  471.       DialogBoxParam (hInst, "WinVnSubject", hWndConf, lpfnWinVnSubjectDlg, (LPARAM)(NewDocType == DOCTYPE_POSTING));
  472.     }
  473.  
  474.   CopyBuf (DialogString, &outptr, &BufLen);
  475.   return (TRUE);
  476. }
  477.  
  478. /*--- function GetArtHeaderSubject -------------------------------------
  479.  *
  480.  *    Fill the DialogString global variable if a subject can be extracted
  481.  *    of the form  "Subject: Re: <previous subject>".
  482.  *    If the article being replied to had a subject already starting
  483.  *    with "Re:", the "Re:" is not repeated.
  484.  *    returns FALSE as no line assembled
  485.  *    if no previous subject is found SubjestString is ""
  486.  */
  487.  
  488. GetArtHeaderSubject (Doc, NA, NALen)
  489.      TypDoc *Doc;
  490.      char *NA;
  491.      long int NALen;
  492. {
  493.   char HeadLine[MAXHEADERLINE];
  494.   char *outptr = DialogString ; 
  495.   char *headptr = HeadLine;
  496.   long int BufLen = MAXDIALOGSTRING ;
  497.  
  498.   *outptr='\0' ;
  499.   if (Doc && ( GetHeaderLine (Doc, "Subject:", HeadLine, MAXHEADERLINE)))
  500.      {
  501.    NextToken (&headptr);
  502.    if (CompareStringNoCase (headptr, "Re:", 3) != 0)
  503.         {
  504.         CopyBuf ("Re: ", &outptr, &BufLen);
  505.          }
  506.    CopyBuf (headptr, &outptr, &BufLen);
  507.      }
  508.  
  509.    return(FALSE) ;
  510. }
  511. #if 0
  512. /*--- function MakeArtHeaderMessageID ----------------------------------
  513.  *
  514.  *    Returned "Message-ID:" line is computed from the time and
  515.  *    the ServerName (from Windows profile file).  This needs to
  516.  *    be improved.
  517.  */
  518. BOOL
  519. MakeArtHeaderMessageID (Doc, Buf, BufLen)
  520.      TypDoc *Doc;
  521.      char *Buf;
  522.      long int BufLen;
  523. {
  524. #define MAXSERVERNAME 32
  525.   char ServerName[MAXSERVERNAME];
  526.  
  527.   GetPrivateProfileString (szAppName, "ServerName", "titan.ksc.nasa.gov",
  528.           ServerName, MAXSERVERNAME, szAppProFile);
  529.  
  530.   sprintf (Buf, "Message-ID: <%ld@%s>", time ((time_t *) NULL), ServerName);
  531.   return TRUE;
  532. }
  533.  
  534. #endif
  535.  
  536. /*--- function MakeArtHeaderFrom ----------------------------------
  537.  *
  538.  *  Returned "From:" is taken from Windows profile entries.
  539.  */
  540. BOOL
  541. MakeArtHeaderFrom (Doc, Buf, BufLen)
  542.      TypDoc *Doc;
  543.      char *Buf;
  544.      long int BufLen;
  545. {
  546.   char *outptr = Buf;
  547.  
  548.   CopyBuf ("From: ", &outptr, &BufLen);
  549.   if (MailAddress[0])
  550.     {
  551.       CopyBuf (MailAddress, &outptr, &BufLen);
  552.     }
  553.   else
  554.     {
  555.       CopyBuf ("<Unknown>", &outptr, &BufLen);
  556.     }
  557.   if (UserName[0])
  558.     {
  559.       CopyBuf (" (", &outptr, &BufLen);
  560.       CopyBuf (UserName, &outptr, &BufLen);
  561.       CopyBuf (")", &outptr, &BufLen);
  562.     }
  563.  
  564.   return TRUE;
  565. }
  566.  
  567. /*--- function MakeArtHeaderReplyTo -------------------------------
  568.  *
  569.  *  Returned "Reply-To:" is taken from Windows profile entries.
  570.  */
  571. BOOL
  572. MakeArtHeaderReplyTo (Doc, Buf, BufLen)
  573.      TypDoc *Doc;
  574.      char *Buf;
  575.      long int BufLen;
  576. {
  577.   char *outptr = Buf;
  578.  
  579.   if (ReplyTo[0] && strcmp(ReplyTo, MailAddress))
  580.     {
  581.       CopyBuf ("Reply-To: ", &outptr, &BufLen);
  582.       CopyBuf (ReplyTo, &outptr, &BufLen);
  583.       return TRUE;
  584.     }
  585.   return FALSE;
  586. }
  587.  
  588. /*--- function MakeArtHeaderTo ----------------------------------
  589.  *
  590.  *  Returns a well formed "To:" line or if user selected cancel
  591.  *  returns "To:" (blank) which if not edited will be rejected by
  592.  *  the server.
  593.  */
  594. BOOL
  595. MakeArtHeaderTo (Doc, Buf, BufLen)
  596.      TypDoc *Doc;
  597.      char *Buf;
  598.      long int BufLen;
  599. {
  600.   char HeadLine[MAXHEADERLINE];
  601.   char *outptr = Buf, *cptr = HeadLine;
  602.   GetArtHeaderTo(Doc,NULL,NULL);  
  603.  
  604.   if (!strcmp(AddressString, "")) {
  605.  
  606.     DialogString[0]=(char)NULL;
  607.     while (!strcmp(DialogString,""))
  608.       if (!DialogBox (hInst, "WinVnMail", hWndConf, lpfnWinVnMailDlg))
  609.         break;  
  610.         
  611.     sprintf(HeadLine,"To: %s", DialogString);
  612.   }
  613.   else
  614.     sprintf(HeadLine,"To: %s", AddressString);
  615.  
  616.   CopyBuf (HeadLine, &outptr, &BufLen);
  617.   return TRUE;
  618. }
  619.  
  620. /*--- function GetArtHeaderTo ----------------------------------
  621.  *
  622.  *    Simply returns contents for a "To:"  Line
  623.  *
  624.  *    Global Variables
  625.  *    NameString and AddressString are extracted from the Document
  626.  *    returns FALSE as no line has been assembled
  627.  */
  628. BOOL
  629. GetArtHeaderTo (Doc, NA, NALen)
  630.      TypDoc *Doc;
  631.      char *NA;
  632.      long int NALen;
  633. {
  634.   char HeadLine[MAXHEADERLINE];
  635.   char *cptr = HeadLine ;
  636.   BOOL gotwho;
  637.   char ReplyAddress[MAXDIALOGSTRING], ReplyName[MAXDIALOGSTRING];
  638.  
  639.   if (Doc)
  640.     {
  641.       if (GetHeaderLine (Doc, "From:", HeadLine, MAXHEADERLINE))
  642.          {
  643.         NextToken (&cptr);
  644.         ParseAddress (cptr, AddressString,MAXDIALOGSTRING , NameString,MAXDIALOGSTRING ) ;
  645.          }
  646.       if (gotwho = GetHeaderLine (Doc, "Reply-To:", HeadLine, MAXHEADERLINE))
  647.      {
  648.         NextToken (&cptr);
  649.         ParseAddress (cptr, ReplyAddress,MAXDIALOGSTRING , ReplyName,MAXDIALOGSTRING ) ;
  650.      }
  651.       if (gotwho && strcmp (AddressString, ReplyAddress))
  652.          {
  653.             if (AddressString[0] && ConfirmReplyTo)
  654.             { 
  655.                sprintf (str, "Use Reply-To: (%s) instead of\nFrom: (%s) in reply?", 
  656.                         ReplyAddress, AddressString);
  657.                       
  658.                if (MessageBox (Doc->hDocWnd, str, "Confirm Reply-To", 
  659.                                MB_YESNO|MB_ICONQUESTION) == IDNO)
  660.                   gotwho = FALSE;
  661.             }
  662.             if (gotwho)
  663.                strcpy (AddressString, ReplyAddress);
  664.          }
  665.       }
  666.  
  667.   return FALSE;
  668. }
  669. /*--- function ParseAddress --------------------------
  670.  *   Scan the
  671.  *       address field (null terminated ascii string)
  672.  *  representing any email address and optional
  673.  *       name
  674.  *
  675.  *   and extract
  676.  *   addressout which is the email address
  677.  *   nameout    which is the name (enclosed in parenthises)
  678.  *
  679.  *--------------------------------------------------------*/
  680. void ParseAddress(headerline,addressout,addressoutlen,nameout,nameoutlen)
  681.  char *headerline ;
  682.  char *addressout ;
  683.  long int addressoutlen ;
  684.  char *nameout ;
  685.  long int nameoutlen ;
  686. { char *ptra = headerline , *ptrb, *ptrc ;
  687.   char *iptr , *optr;
  688.   int  lastspace ;
  689.   long int adlen = addressoutlen - 1 ,nmlen = nameoutlen -1 ;
  690.   long int l;
  691.  
  692.    nameout[0]=addressout[0]=0 ;
  693.  
  694. // Note parsing not strictly correct as anything in quotes '"'
  695. // overrides the meaning of lexical constructs '<' and '('
  696.  
  697. // Seems this works and is robust but is now in the main
  698. // group list read and should be extremely efficient
  699. // suggest a single pass 'stream' parse more appropriate
  700. // but is more work
  701.  
  702.   if (ptrb=strchr(headerline,'<'))
  703.   {  // address enclosed in brackets  
  704.      l=min(ptrb-ptra-1,nmlen) ;
  705.      if (l < 0) l = 0;     /* this was killing print??? */
  706.      if (l>0)
  707.      {                      // otherwise strncpy crashes
  708.         nmlen-=l ;
  709.         strncpy(nameout,ptra,(int)l) ;
  710.         nameout[l]=0;
  711.      }
  712.      if(  ptrc=strchr(headerline,'>') )
  713.      {
  714.    if (nmlen >0)
  715.         {
  716.       strncpy(nameout+l,ptrc+1,(int)nmlen) ;
  717.       nameout[nameoutlen-1]=0 ;
  718.    }
  719.    l=min(ptrc-ptrb-1,adlen) ;
  720.      } else
  721.      {
  722.    l=adlen ;
  723.      }
  724.      if (l>0)
  725.      {
  726.      strncpy(addressout,ptrb+1,(int)l);
  727.      addressout[l]=0;
  728.      }
  729.  
  730.   } else
  731.     if (ptrb=strchr(headerline,'('))
  732.   {  // name enclosed in braces
  733.      l=min(ptrb-ptra-1,adlen) ;
  734.      if (l>0)
  735.      {
  736.         adlen-=l ;
  737.    strncpy(addressout,ptra,(int)l) ;
  738.         addressout[l+1]=0;
  739.      }
  740.      if( ptrc=strchr(headerline,')'))
  741.      {
  742.    if (adlen > 0)
  743.         {
  744.       strncpy(addressout+l,ptrc+1,(int)adlen) ;
  745.       addressout[addressoutlen-1]=0 ;
  746.         }
  747.    l=min(ptrc-ptrb-1,nmlen) ;
  748.      } else
  749.      {
  750.    l=nmlen ;
  751.      }
  752.      if (l>0)
  753.      {
  754.      strncpy(nameout,ptrb+1,(int)l);
  755.      nameout[l]=0;
  756.      }      
  757.  
  758.   } else
  759.   { // just an address
  760.      strncpy(addressout,ptra,(int)adlen) ;
  761.      addressout[addressoutlen-1]=0 ;
  762.   }
  763.  
  764. // Clean Name   - remove multiple space and quotes
  765.   lastspace=TRUE ;
  766.   for(iptr=optr=nameout ; *iptr ; iptr++)
  767.   {  switch( *iptr)
  768.      {
  769.        case ' ':
  770.     if (!lastspace) *optr++=*iptr ;
  771.     lastspace=TRUE ;
  772.          break;
  773.        case '"':    
  774.     break ;
  775.        default :
  776.     *optr++=*iptr ;
  777.     lastspace=FALSE ;
  778.       }
  779.    }
  780.    *optr=0 ;
  781.  
  782. // Clean Address
  783.   for(iptr=optr=addressout ; *iptr ; iptr++)
  784.   {  switch( *iptr)
  785.      {
  786.        case ' ':
  787.          break;
  788.        default :
  789.     *optr++=*iptr ;
  790.     lastspace=FALSE ;
  791.       }
  792.    }
  793.    *optr=0 ;
  794.  
  795.    if (*nameout==0)
  796.    {  // if no name default to address
  797.       strncpy(nameout,addressout,(int)nmlen) ;
  798.       addressout[nameoutlen-1]=0 ;
  799.    }
  800.  
  801.  }
  802.  
  803. /*  original code for parsing address
  804.   char *adptr = addressout, *nmptr=nameout, *cptr = headerline;
  805.   char *tptr ;
  806.  
  807.  
  808.   if ( *cptr == '(' )
  809.   {                         //  skip Name in brackets 
  810.       tptr =  strchr(headerline,')') ;
  811.       if (tptr != NULL) cptr=tptr ;
  812.       NextToken(&cptr);     // skip parenthesis and white space
  813.   }     
  814.   while (*cptr && *cptr != ' ' && adlen)
  815.   {
  816.       *(adptr++) = *(cptr++);
  817.       adlen-- ;
  818.   }
  819.   *adptr = '\0';
  820.  
  821.   cptr = strchr(headerline,'(');
  822.   if (cptr != NULL) 
  823.   {
  824.        cptr++;                                  // skip (    
  825.        while (*cptr && *cptr != ')' && nmlen)   // copy to ) 
  826.        {
  827.        if (*cptr != '"')                   // drop quote characters 
  828.             {
  829.           *(nmptr++) = *(cptr);
  830.           nmlen--;
  831.        }
  832.             cptr++ ;
  833.        }
  834.        *nmptr = '\0';
  835.    }
  836.    else
  837.    {
  838.    strncpy( nmptr,addressout,(int)nmlen)  ;
  839.    nmptr[nmlen+1]= '\0' ;
  840.   }
  841.  
  842. }
  843.  
  844. */
  845.  
  846. /*--- function MakeArtHeaderOrganization ----------------------------------
  847.  *
  848.  *    Returned "Organization:" line is gotten from the Windows
  849.  *    profile file.
  850.  */
  851. BOOL
  852. MakeArtHeaderOrganization (Doc, Buf, BufLen)
  853.      TypDoc *Doc;
  854.      char *Buf;
  855.      long int BufLen;
  856. {
  857.   char *outptr = Buf;
  858.  
  859.   if (Organization[0])
  860.     {
  861.       CopyBuf ("Organization: ", &outptr, &BufLen);
  862.       CopyBuf (Organization, &outptr, &BufLen);
  863.       return (TRUE);
  864.     }
  865.  
  866.   return FALSE;
  867. }
  868.  
  869. /*--- function MakeArtHeaderNewsreader ----------------------------------
  870.  *
  871.  *    Returned "Newsreader: " line is simply a constant.
  872.  */
  873. BOOL
  874. MakeArtHeaderNewsreader (Doc, Buf, BufLen)
  875.      TypDoc *Doc;
  876.      char *Buf;
  877.      long int BufLen;
  878. {
  879.   char *outptr = Buf;
  880.  
  881.   CopyBuf ("X-Newsreader: ", &outptr, &BufLen);
  882.   CopyBuf (WINVN_VERSION, &outptr, &BufLen);
  883. /* easier than examining this closely */
  884. /*  CopyBuf ("\r", &outptr , &BufLen); */
  885.   return (TRUE);
  886.  
  887. }
  888.  
  889. /*--- function MakeArtHeaderXmailer ----------------------------------
  890.  *
  891.  *    Returned "Mailer: " line is simply a constant.
  892.  */
  893. BOOL
  894. MakeArtHeaderXmailer (TypDoc * Doc, char *Buf, long int BufLen)
  895. {
  896.   char *outptr = Buf;
  897.  
  898.   CopyBuf ("X-Mailer: ", &outptr, &BufLen);
  899. //  CopyBuf ("WinVN version 0.82 SMTP", &outptr, &BufLen);
  900.   CopyBuf (WINVN_VERSION, &outptr, &BufLen);
  901.   return (TRUE);
  902. }
  903.  
  904.  
  905. /*--- function MakeArtHeaderDate ----------------------------------
  906.  *
  907.  *    Returned "Date:" line is computed from operating system time.
  908.  *    Be sure to set the TZ environment variable correctly for
  909.  *    "gmtime" to work properly.  Typical setting:  SET TZ=EST5
  910.  */
  911. BOOL
  912. MakeArtHeaderDate (Doc, Buf, BufLen)
  913.      TypDoc *Doc;
  914.      char *Buf;
  915.      long int BufLen;
  916. {
  917.   struct tm *timeptr;
  918.   time_t curtime;
  919.   static char * days[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  920.   static char * months[] = { "Jan","Feb","Mar","Apr","May","Jun",
  921.                 "Jul","Aug","Sep","Oct","Nov","Dec"};
  922.  
  923.  
  924.   if (!getenv("TZ")) {
  925.     MessageBox (hWndConf,
  926.       "Timezone environment variable 'TZ' not set.\n"
  927.       "You must set this variable for your messages\n"
  928.       "to be timestamped correctly.\n"
  929.       "For example, you could add the following to your\n"
  930.       "'autoexec.bat' file:\n"
  931.       "set TZ=EST5EDT\n",
  932.       "Warning:",
  933.       MB_OK|MB_ICONHAND);
  934.   }
  935.  
  936.   curtime = time ((time_t *) NULL);
  937.   timeptr = localtime (&curtime);
  938.   
  939.   /* rfc1036&rfc822 acceptable format */
  940.   /* Mon, 29 Jun 93 02:15:23 GMT */
  941.   sprintf (Buf, "Date: %s, %.2d %s %.2d %.2d:%.2d:%.2d %s",
  942.       days[timeptr->tm_wday],
  943.       timeptr->tm_mday,
  944.       months[timeptr->tm_mon],
  945.       timeptr->tm_year,
  946.       timeptr->tm_hour,
  947.       timeptr->tm_min,
  948.       timeptr->tm_sec,
  949.       tzname[0]);
  950.   return TRUE;
  951. }
  952.  
  953.  
  954. /*--- function MakeArtHeaderReferences -----------------------------------
  955.  *
  956.  *  Returned "References:" line contains all the previous article's
  957.  *  References (if any), plus its Message-ID (if any).
  958.  */
  959. BOOL
  960. MakeArtHeaderReferences (Doc, Buf, BufLen)
  961.      TypDoc *Doc;
  962.      char *Buf;
  963.      long int BufLen;
  964. {
  965.   char HeadLine[MAXHEADERLINE];
  966.   BOOL gotrefs;
  967.   BOOL gotmesID;
  968.   char *outptr = Buf;
  969.   char *headptr = HeadLine;
  970.  
  971.  
  972.   if (Doc)
  973.     {
  974.       gotrefs = GetHeaderLine (Doc, "References:", HeadLine, MAXHEADERLINE);
  975.       if (gotrefs)
  976.    {
  977.      CopyBuf (HeadLine, &outptr, &BufLen);
  978.      CopyBuf (" ", &outptr, &BufLen);
  979.    }
  980.       gotmesID = GetHeaderLine (Doc, "Message-ID:", HeadLine, MAXHEADERLINE);
  981.       if (gotmesID)
  982.    {
  983.      if (!gotrefs)
  984.        {
  985.          CopyBuf ("References: ", &outptr, &BufLen);
  986.        }
  987.      NextToken (&headptr);
  988.      CopyBuf (headptr, &outptr, &BufLen);
  989.    }
  990.       if (gotrefs || gotmesID)
  991.    return (TRUE);
  992.     }
  993.   return FALSE;
  994. }
  995.  
  996. /*--- function MakeArtHeaderNewsgroups -----------------------------------
  997.  *
  998.  *  Returned "Newsgroups:" line is simply a copy of previous article's.
  999.  */
  1000. BOOL
  1001. MakeArtHeaderNewsgroups (Doc, Buf, BufLen)
  1002.      TypDoc *Doc;
  1003.      char *Buf;
  1004.      long int BufLen;
  1005. {
  1006.   char HeadLine[MAXHEADERLINE];
  1007.   BOOL gotnews = FALSE;
  1008.   char *outptr = Buf;
  1009.  
  1010.   if (Doc)
  1011.     {
  1012.       gotnews = GetHeaderLine (Doc, "Newsgroups:", HeadLine, MAXHEADERLINE);
  1013.       if (gotnews)
  1014.    {
  1015.      CopyBuf (HeadLine, &outptr, &BufLen);
  1016.    }
  1017.     }
  1018.   if (!gotnews)
  1019.     {
  1020.       CopyBuf ("Newsgroups: ", &outptr, &BufLen);
  1021.       CopyBuf (NewsgroupsPtr, &outptr, &BufLen);
  1022.     }
  1023.   return TRUE;
  1024. }
  1025.  
  1026. /*--- function MakeArtBody ----------------------------------------------
  1027.  *
  1028.  *    Make the body of the article.  This is null if there's no article
  1029.  *    to reply to, else it's text of the form:
  1030.  *    In article <Message-ID>, <user> says:
  1031.  *    >line 1
  1032.  *    >line 2
  1033.  *    > .....
  1034.  *
  1035.  *    Entry    Doc      points to the article being replied to, else
  1036.  *                      NULL if none.
  1037.  *             left     is the number of bytes left in MesBuf.
  1038.  *
  1039.  *    Exit     MesBuf   contains the added lines, and has been updated
  1040.  *                      to point to just after the last added byte.
  1041.  *             left     has been decremented appropriately.
  1042.  *             Return value is not used, for now.
  1043.  */
  1044. BOOL 
  1045. MakeArtBody (Doc, MesBuf, left, DocType)
  1046.      TypDoc *Doc;
  1047.      char far **MesBuf;
  1048.      long int *left;
  1049.      int DocType;
  1050. {
  1051.   HANDLE hBlock;
  1052.   unsigned int Offset;
  1053.   TypLineID MyLineID;
  1054.   TypBlock far *BlockPtr;
  1055.   TypLine far *LinePtr;
  1056.   char mesID[MAXHEADERLINE];
  1057.   char from[MAXHEADERLINE];
  1058.   char line[MAXHEADERLINE];
  1059.   BOOL gotmesID, gotfrom;
  1060.   char *outptr = line;
  1061.   char *fromptr = from;
  1062.   char *mesptr = mesID;
  1063.   register unsigned long i;
  1064.   
  1065.   AppendTextToEditBuf ("", MesBuf, left); /* blank line after header */
  1066.  
  1067.   /* Create the "In message xxx, yyy says:" line.                   */
  1068.  
  1069.   if (Doc)
  1070.     {
  1071.       gotmesID = GetHeaderLine (Doc, "Message-ID:", mesID, MAXHEADERLINE);
  1072.       if (gotmesID)
  1073.    {
  1074.      NextToken (&mesptr);
  1075.    }
  1076.       else
  1077.    {
  1078.      mesptr = "<Unknown>";
  1079.    }
  1080.       switch (DocType) {
  1081.       case DOCTYPE_POSTING:
  1082.    gotfrom = GetHeaderLine (Doc, "From:", from, MAXHEADERLINE);
  1083.    if (gotfrom)
  1084.        NextToken (&fromptr);
  1085.    else
  1086.          fromptr = "<Unknown>";
  1087.    sprintf (line, "In article %s, %s says:", mesptr, fromptr);
  1088.    break;
  1089.  
  1090.       case DOCTYPE_MAIL:
  1091.    sprintf (line, "In article %s, you say:", mesptr);
  1092.    break;
  1093.       }
  1094.  
  1095.       AppendTextToEditBuf (line, MesBuf, left);
  1096.  
  1097.       /* Skip past header of reply document.                            */
  1098.  
  1099.       TopOfDoc (Doc, &BlockPtr, &LinePtr);
  1100.       while (ExtractTextLine (Doc, LinePtr, line, MAXHEADERLINE) &&
  1101.         !IsLineBlank (line))
  1102.    {
  1103.      if (!NextLine (&BlockPtr, &LinePtr))
  1104.        break;
  1105.    }
  1106.  
  1107.       /* Copy body of reply document into the body of this article,  */
  1108.       /* prepending a ">" to each line */
  1109.  
  1110.       /* following line commented after a merge of MRB code (SMR)*/
  1111.       /* line[0] = '>'; */
  1112.  
  1113.       line[0] = QuoteLineInd ;
  1114.  
  1115.       while (ExtractTextLine (Doc, LinePtr, line + 1, MAXHEADERLINE - 1))
  1116.    {
  1117.      AppendTextToEditBuf (line, MesBuf, left);
  1118.      if (!NextLine (&BlockPtr, &LinePtr))
  1119.        break;
  1120.    }
  1121.       UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
  1122.       if (EnableSig && Signature->numLines > 0)
  1123.         AppendTextToEditBuf ("", MesBuf, left); /* blank line before sig */
  1124.     }
  1125.  
  1126.   if (EnableSig)
  1127.     {
  1128.    for (i = 0; i < Signature->numLines; i++)
  1129.      AppendTextToEditBuf (TextBlockLine(Signature, i), MesBuf, left);
  1130.     }
  1131.   return TRUE;
  1132. }
  1133.  
  1134.  
  1135. /*--- function CompareStringNoCase -------------------------------------
  1136.  *
  1137.  *   Compare two strings, case insensitive.
  1138.  *
  1139.  *    Entry    str1, str2  are two strings to compare.
  1140.  *             slen        is the number of characters to compare
  1141.  *                         (but stop at a zero byte).
  1142.  *
  1143.  *    Exit     returns -1 if str1 is earlier in collating sequence,
  1144.  *              0 if strings are equal, 1 otherwise
  1145.  */
  1146. int
  1147. CompareStringNoCase (str1, str2, slen)
  1148.      char *str1;
  1149.      char *str2;
  1150.      int slen;
  1151. {
  1152. /* bug when either string is zero length mrb */
  1153.   if (strlen(str1) < (unsigned) slen)
  1154.      {
  1155.    return(-1)  ;
  1156.       }
  1157.   if (strlen(str2) < (unsigned) slen)
  1158.      {
  1159.        return(+1) ;
  1160.      }
  1161.  
  1162.   while (slen-- && *str1 && *str2)
  1163.     {
  1164.       if (tolower (*str1) < tolower (*str2))
  1165.    {
  1166.      return (-1);
  1167.    }
  1168.       else if (tolower (*str1) > tolower (*str2))
  1169.    {
  1170.      return (1);
  1171.    }
  1172.       str1++;
  1173.       str2++;
  1174.     }
  1175.   return (0);
  1176. }
  1177.  
  1178. /*--- function CopyBuf -----------------------------------------------
  1179.  *
  1180.  *    Copy a string into a buffer, being sure not to overrun the
  1181.  *    buffer.
  1182.  *
  1183.  *    Entry    instr    points to the string to copy into the buffer,
  1184.  *                      zero-terminated.
  1185.  *             buf      is the buffer
  1186.  *             left     is the number of bytes left in the buffer
  1187.  *    Exit     buf      contains the LWA+1 of the bytes copied into
  1188.  *                      the output buffer.  A Zero byte is stored
  1189.  *                      into this location.
  1190.  *             left     is the number of bytes left in the buffer.
  1191.  */
  1192.  
  1193. void
  1194. CopyBuf (instr, buf, left)
  1195.      char *instr;
  1196.      char **buf;
  1197.      long int *left;
  1198. {
  1199.   while (--(*left) > 1 && *instr)
  1200.     {
  1201.       *((*buf)++) = *(instr++);
  1202.     }
  1203.   if (*left > 0)
  1204.     **buf = '\0';
  1205. }
  1206.  
  1207. /*--- function NextToken -----------------------------------------------
  1208.  *
  1209.  *  Position a pointer to the next token in a string.
  1210.  *  Delimiters are space and tab.
  1211.  *
  1212.  *    Entry    cptr     points to a position in a zero-terminated string.
  1213.  *
  1214.  *    Exit     Returns TRUE iff a next token was found.
  1215.  *             cptr     points to the next token, if found--else
  1216.  *                      it is unchanged.
  1217.  */
  1218. BOOL
  1219. NextToken (cptr)
  1220.      char **cptr;
  1221. {
  1222.   /* Skip to end of current token, if any.              */
  1223.  
  1224.   while (**cptr != ' ' && **cptr != '\t' && **cptr)
  1225.     (*cptr)++;
  1226.  
  1227.   /* Skip past white space.                             */
  1228.  
  1229.   while (**cptr && (**cptr == ' ' || **cptr == '\t'))
  1230.     (*cptr)++;
  1231.   if (**cptr)
  1232.     {
  1233.       return (TRUE);
  1234.     }
  1235.   else
  1236.     {
  1237.       return (FALSE);
  1238.     }
  1239. }
  1240.  
  1241. /*--- function AppendTextToEditBuf ----------------------------------------
  1242.  *
  1243.  *    Appends a zero-terminated text line to a buffer to be given
  1244.  *    to an Edit window.  Used in building messages to be displayed
  1245.  *    and edited by an Edit window.
  1246.  *
  1247.  *    Entry    instr    points to a text line to add.  It is terminated
  1248.  *                      by a zero byte and does not end in CR or LF.
  1249.  *             left     is the number of characters left in buf.
  1250.  *
  1251.  *    Exit     buf      contains the line, terminated by CR and LF.
  1252.  *                      buf now points to the next available byte.
  1253.  *             left     has been decremented as appropriate.
  1254.  */
  1255. void
  1256. AppendTextToEditBuf (instr, buf, left)
  1257.      char *instr;
  1258.      char far **buf;
  1259.      long int *left;
  1260. {
  1261.   while (--(*left) > 0 && *instr)
  1262.     {
  1263.       *((*buf)++) = *(instr++);
  1264.     }
  1265.   if (--(*left) > 0)
  1266.     *((*buf)++) = '\r';
  1267.  
  1268.   if (--(*left) > 0)
  1269.     *((*buf)++) = '\n';
  1270.  
  1271.   if ((*left) > 0)
  1272.     **buf = '\0';
  1273. }
  1274.  
  1275. /*--- function IsLineBlank ------------------------------------------------
  1276.  *
  1277.  *    Determine whether a zero-terminated line is blank.
  1278.  *    "Blank" means it contains nothing but spaces and tabs.
  1279.  *
  1280.  *    Entry    line     points to the line.
  1281.  *
  1282.  *    Exit     returns TRUE iff the line is blank.
  1283.  */
  1284. BOOL
  1285. IsLineBlank (line)
  1286.      char far *line;
  1287. {
  1288.   while (*line == ' ' || *line == '\t' || *line == '\n')
  1289.     line++;
  1290.   return (!(*line));
  1291. }
  1292.  
  1293. /*------------ editIntercept ---------------------------------- 
  1294.  *
  1295.  *   the subclassed WindowProc for the edit component
  1296.  *
  1297.  *   Capture key messages and pass them to parent
  1298.  * as may contain accelerator information
  1299.  *
  1300.  *--------------------------------------------------------------*/
  1301.  
  1302. BOOL FAR PASCAL  editIntercept(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1303.   HWND  parWnd ;
  1304.   BOOL res ;
  1305.  
  1306.   if (msg == WM_KEYDOWN || msg == WM_KEYUP)
  1307.     /* if it receives a keyboard event, pass it to your parent */
  1308.     {
  1309.      parWnd = GetParent(hwnd);
  1310.       res =  PostMessage(parWnd,msg, wParam,lParam );
  1311.     }
  1312.   /* and always let the edit control do its thing  */
  1313.   return (BOOL) CallWindowProc((WNDPROC)GetClassLong(hwnd, GCL_WNDPROC),
  1314.                 hwnd, msg, wParam , lParam);
  1315. }
  1316.  
  1317. /* --------------- prepareEditMenu -----------------
  1318.  *
  1319.  *  Common (wvpost and wvmail) preparartion
  1320.  *  of edit menus 
  1321.  *
  1322.  * ------------------------------------------------- 
  1323.  */
  1324.  
  1325. void  prepareEditMenu(HWND parWnd,HWND hWndEdit) 
  1326.  
  1327. {  DWORD dwResult ;
  1328.    UINT action;
  1329.    HMENU hMenu = GetMenu(parWnd);
  1330.  
  1331.    dwResult = SendMessage (hWndEdit, EM_GETSEL, 0, 0L);
  1332.  
  1333.    if ( HIWORD (dwResult) == LOWORD (dwResult) )
  1334.    {   /* No selection to ROT,Copy or Cut */
  1335.        action=MF_GRAYED ;
  1336.    } else
  1337.    {
  1338.        action=MF_ENABLED ;
  1339.    }
  1340.    EnableMenuItem(hMenu,IDM_ROT13,action) ;
  1341.    EnableMenuItem(hMenu,IDM_COPY,action) ;
  1342.    EnableMenuItem(hMenu,IDM_CUT,action) ;
  1343.    EnableMenuItem(hMenu,IDM_CLEAR,action) ;
  1344.  
  1345.    if (IsClipboardFormatAvailable(CF_TEXT))
  1346.    { 
  1347.       action=MF_ENABLED ;
  1348.    } else
  1349.    {   /* No Clip board contents to paste */
  1350.       action=MF_GRAYED ;
  1351.    }
  1352.    EnableMenuItem(hMenu,IDM_PASTE,action) ;
  1353.  
  1354.  
  1355.   if (SendMessage (hWndEdit, EM_CANUNDO, 0, 0L))
  1356.   { 
  1357.      action=MF_ENABLED ;
  1358.   } else
  1359.   {  /* Undo Buffer is empty so cannot Undo changes */
  1360.      action=MF_GRAYED ;
  1361.   }
  1362.   EnableMenuItem(hMenu,IDM_UNDO,action) ;
  1363.  
  1364. }
  1365.  
  1366. /* ---------------- function DoEditCommands -------------
  1367.  *
  1368.  *  Command edit commands between wvpost and wvmail
  1369.  *
  1370.  * ------------------------------------------------------*/
  1371. DoEditCommands(HWND hWndEdit,WPARAM wParam,LPARAM lParam)
  1372. {
  1373.       switch (LOWORD(wParam))
  1374.    {
  1375.    case IDM_UNDO:
  1376.      SendMessage (hWndEdit, WM_UNDO, 0, 0L);
  1377.      break;
  1378.  
  1379.    case IDM_CUT:
  1380.      SendMessage (hWndEdit, WM_CUT, 0, 0L);
  1381.      break;
  1382.  
  1383.    case IDM_COPY:
  1384.      SendMessage (hWndEdit, WM_COPY, 0, 0L);
  1385.      break;
  1386.  
  1387.    case IDM_PASTE:
  1388.      SendMessage (hWndEdit, WM_PASTE, 0, 0L);
  1389.      break;
  1390.  
  1391.    case IDM_CLEAR:
  1392.      SendMessage (hWndEdit, WM_CLEAR, 0, 0L);
  1393.      break;
  1394.  
  1395.    case IDM_SELALL:
  1396.      SendMessage (hWndEdit, EM_SETSEL, 0,
  1397.              MAKELONG (0, 32767));
  1398.      break;
  1399.  
  1400.    case IDM_ROT13:
  1401.      { DWORD dwResult ;
  1402.        WORD  wStart, wEnd ;
  1403.             char *editptr;
  1404.  
  1405.        dwResult = SendMessage (hWndEdit, EM_GETSEL, 0, 0L);
  1406.        wStart = LOWORD (dwResult) ;
  1407.        wEnd   = HIWORD (dwResult) ;
  1408.  
  1409.        editptr = GetEditText (hWndEdit);
  1410.        strnROT13(editptr + wStart, wEnd - wStart) ;
  1411.             SetEditText (hWndEdit, editptr);
  1412.             GlobalFreePtr (editptr);
  1413.        InvalidateRect (hWndEdit, NULL, TRUE);
  1414.      }
  1415.      break;
  1416.  
  1417.         default :
  1418.           return(0) ;   // signnify no action 
  1419.    }
  1420.    return(1) ;          // signify actions completed 
  1421.  }
  1422.  
  1423. /*
  1424.  *  function DoEditClose
  1425.  *  close down the edit window only if clean to close 
  1426.  *  or user agrees to lose information 
  1427.  *
  1428.  */
  1429.  
  1430.  void DoEditClose(HWND hWnd,int dirty)
  1431.  {
  1432.    if ( dirty == DT_DIRTY)
  1433.    {
  1434.      if (MessageBox(hWnd, "Are you sure you want to exit?", "Unsaved Work",
  1435.     MB_ICONQUESTION | MB_OKCANCEL) == IDOK)
  1436.     DestroyWindow(hWnd);
  1437.    }
  1438.    else
  1439.       DestroyWindow(hWnd);
  1440.  }
  1441.